/*************************************************************************
	> File Name: test.h
	> Author: Maureen 
	> Mail: Maureen@qq.com 
	> Created Time: 一  8/30 15:47:29 2021
 ************************************************************************/
#include <maureen/linklist.h>

#ifndef _TEST_H
#define _TEST_H


#define CORLOR(a, b) "\033[" #b "m" a "\033[0m"
#define CORLOR_HL(a, b) "\033[1;" #b "m" a "\033[0m"
#define GREEN(a) CORLOR(a, 32)
#define RED(a) CORLOR(a, 31)
#define BLUE(a) CORLOR(a, 34)
#define YELLOW(a) CORLOR(a, 33)

#define GREEN_HL(a) CORLOR_HL(a, 32)
#define RED_HL(a) CORLOR_HL(a, 31)
#define BLUE_HL(a) CORLOR_HL(a, 34)
#define YELLOW_HL(a) CORLOR_HL(a, 33)


#define TEST(a, b) \
void a##_maureen_##b(); \
__attribute__((constructor)) \
void add##_maureen_##a##_maureen_##b() { \
    add_function(a##_maureen_##b, #a"."#b); \
}\
void a##_maureen_##b()

//泛型宏
#define TYPE(a) _Generic((a), \
    int : "%d",\
    double : "%lf", \
    float : "%f", \
    long long : "%lld", \
    const char * : "%s", \
    char * : "%s" \
)

#define P(a, color) { \
    char frm[1000]; \
    sprintf(frm, color("%s"), TYPE(a)); \
    printf(frm, a); \
}

#define EXPECT(a, b, comp) {\
    func_info.total += 1; \
    __typeof(a) _a = (a);\
    __typeof(b) _b = (b);\
    if (_a comp _b) func_info.success += 1;\
    else { \
        printf("\n");\
        printf(YELLOW_HL("\t%s:%d: Failure\n"), __FILE__, __LINE__);\
        printf(YELLOW_HL("\t\texpect : " #a " " #comp " " #b "\n\t\t" "actual : "));\
        P(_a, YELLOW_HL);\
        P(" vs ", YELLOW_HL);\
        P(_b, YELLOW_HL);\
        printf("\n\n");\
    }\
    printf(GREEN("[-----------] ") #a " " #comp " " #b); \
    printf(" %s\n", (_a) comp (_b) ? GREEN_HL("True") : RED_HL("False"));\
}

#define EXPECT_EQ(a, b) EXPECT(a, b, ==)
#define EXPECT_NE(a, b) EXPECT(a, b, !=)
#define EXPECT_LT(a, b) EXPECT(a, b, <)
#define EXPECT_LE(a, b) EXPECT(a, b, <=)
#define EXPECT_GT(a, b) EXPECT(a, b, >)
#define EXPECT_GE(a, b) EXPECT(a, b, >=)

typedef void (*TestFunc)(); //TestFunc被提升为函数指针类型

typedef struct Function { //记录函数信息
    struct LinkNode link_node; //使用链表外骨骼
    TestFunc func;
    const char *func_name;
} Function;

struct FunctionInfo { //记录每组测试用例中的测试点的个数以及成功个数
    int total;
    int success;
};
extern struct FunctionInfo func_info; 

int RUN_ALL_TESTS();

void add_function(TestFunc, const char *); //第一个参数为函数指针，第二个为函数名

#endif
